1. Field of the Invention
The present invention is related to protection of executable software code from copying by hackers and cloners, and more particularly, to the use of encryption and cryptography for generating of tamper-proof software executable code builds.
2. Description of the Related Art
The problem of prevention of copying of software is one that has great relevance today, particularly where many tools are available to hackers and cloners to copy, reverse assemble, reverse compile code. The problem has been particularly exacerbated in recent years due to the fact that much of the software is now available in downloadable form. Early attempts at creation of tamper-resistant code builds involved relatively simple schemes, such as checksum functions, CRC (cyclic redundancy check) or digital signature functions. As part of the tamper-proof mechanism, the executable code generated a value, such as a checksum, a CRC value or a digital signature hash (digest of a signature) value, from the executable code (in other words, from itself), and compared that value with a value that was stored somewhere within the code. A difference in the two values meant that the copy of the executable file that was being run was a fraudulently obtained one, and the tamper resistance mechanism would abort the execution of the executable file.
A similar digital signature technology is used in email encryption, when the email itself contains a public portion of the key, so that the recipient of the email can be certain that the sender has not faked his identity. The same mechanism is used for assembly verification (assembly signing), to created strong-named assemblies, where the runtime process that installs the assembly and launches its execution can check the signature and confirm that the contents of the assembly has not been tampered with.
In recent years, various cryptographic functions have been used to enhance the protection and the tamper resistance level available to vendors of software. Rather than using relatively simple (in cryptographic terms) functions such as checksums and CRCs, other, more advanced mechanisms have been employed. For example, various hash functions have become more popular, as a means for generating a value (called “hash value”) based on the file (in this case, the executable file). Examples of such hash functions include MD4, MD5, etc. —the nature of the hash functions is such that even a small change in the input, or even a 1 bit change in the input file used to generate the hash function value, will result in a completely different hash function value.
Furthermore, hash functions are an example of “one way functions”—i.e., functions such that knowing the output value, it is virtually impossible to work backwards to generate the original data used to generate the hash function value. Furthermore, with most modern hash functions, which generate 40-bit output values, or 64-bit output values, the probability of two different input files generating the same hash function values (where there are 240 or 264 possible hash function values, or 2160 for some of the stronger hash functions, such as SHA1) is vanishingly small.
.NET assemblies have an optional provision for including tamper resistance (also known as “integrity verification” or “strong-name”) as part of the build. To generate a .NET assembly, source code (such as C++, JAVA, etc.) is converted to what is known as “intermediate language”, or IL, format. The IL code is then assembled into a binary executable file. The mechanism for tamper resistance in the .NET assemblies uses cryptography to embed into the executable public part of key for signing and subsequent verification of assembly integrity by .Net runtime. If the assembly has changed, then the hash would not match the stored value, and the .Net assembly would trigger a strong name verification exception.
.NET metadata stores information relating to the public key and the hash of the public key, and defines whether this build is signed or not signed, using a cryptographic key (using a public key cryptography scheme). The public portion of the key is also located in the executable assembly, at an offset specified by the virtual address in the metadata (see FIG. 1), and its size is defined by the CLIHeader (or COM+ header). The .Net runtime identifies the presence of the signature, and verifies it. If the signature is correct (i.e., the assembly has not been altered), the .Net runtime then launches the assembly.
Thus, if the executable file is signed, the .Net runtime will check that whether or not this is a signed assembly, and then, using the public portion of the key which is also embedded in the binary executable file, will check that the control value generated from the key is the same as the control value generated from the executable binary. If the control values (hashes) do not match, then the attempt to run the executable code will fail.
This scheme, however, has a flaw—the location of the signature and public key that determines whether this build is a signed assembly or an unsigned assembly, is known. A hacker can manually edit the binary (or use any of the variety of tools that permit patching of executable binaries), to zero out that field in the binary file (resulting in a clear or empty signature), so that the executable code, when installing and launching, will consider itself to be an unsigned build. As such, the presence of the public portion of the key in the executable file becomes irrelevant, since the executable binary will never check it. Also, the hacker can generate his own key, and alter the public key portion of the key stored in the binary—in other words, the hacker can generate his own keys, re-sign the assembly, and therefore, sell his own licenses to the assembly, or distribute them for free, adding his own license generator.
After generating an unsigned executable binary, a hacker can then publish the code as freeware, or can add a wrapper around it, which will require a digital signature of its own, or can add his own wrapper around the binary, which will then require a signature from the user—in other words, by doing so, the hacker can get into the business of selling or distributing the same product code, but requiring a license to himself, not to the vendor of the software.
Accordingly, there is a need in the art for a more reliable mechanism of tamper-proofing binary assemblies.